package edu.bu.cs511.p5;

/**
 * Tasks are the general prinicipals of computation that are scheduled
 * by schedulers.  All nodes in the scheduler hierarchy (which is a
 * Composite design pattern) are Tasks, however note that Task is
 * abstract, so you must create either SchedTasks or OpcodeTasks if
 * you want to make a Task.<p/>
 *
 * This interface is the glue that holds the entire hierarchy together
 * as schedulers scheduler Tasks.  Tasks have a parent and that parent
 * is the scheduler that schedules them.  Even the root scheduler has
 * a parent, which is the ThreadManager.  The ThreadManager itself
 * does not have a parent (and is of type SchedTask.)
 *
 * <p/>
 * 2.16.06: Gabriel Parmer
 */
abstract public class Task {
    /**
     * parentSchedTask is the scheduler under which we are running (the parent
     * scheduler).  null if root scheduler.
     */
    private SchedTask parentSchedTask = null;

    /** generally for debugging use */
    private String name = "";
    private boolean debug = false;
    //private boolean debug = true;

    /**
     * This is public as it is not protected by any invariants of this
     * class.  Instead it is used at the discretion of the Schedulers
     * which will use it to store data concerning this task.  A
     * specific scheduler will need to maintain some data specific to
     * each task, such as the priority, or QoS requirements, and this
     * field provides that ability.  See ProportionalScheduler and
     * FPScheduler for examples of creating super-classes of SchedData
     * to hold info about the tasks.
     */
    public SchedData schedData = null;

    /**
     * Constructor for a Task which takes in a parent scheduler.<p/>
     *
     * @MODIFIES sets the parentSchedTask field to schedT
     * <p/>
     * @REQUIRES a SchedTask schedT to be this task's parent
     */
    public Task(SchedTask schedT) {
        setParentSchedTask(schedT);
    }

    /**
     * Set the parent task, or the scheduler that schedules this task,
     * to a specific task.<p/>
     *
     * @REQUIRES schedT is the task to make this task's parent<p/>
     *
     * @MODIFIES save the parent task in this task's data structures.
     */
    public void setParentSchedTask(SchedTask schedT) {
        parentSchedTask = schedT;
    }

    /**
     * Retrieve this task's parent task.<p/>
     *
     * @EFFECTS return this task's parent, or null if the parent
     * hasn't been set.
     */
    public SchedTask getParentScheduler() {
        return parentSchedTask;
    }

    /**
     * Set the name of the task.  This is useful for debugging and
     * testing when you wish to identify which task you are working
     * with in a human-readable manner.<p/>
     *
     * @REQUIRES n is the identification string and should not be
     * null.<p/>
     *
     * @MODIFIES name is updated to reflect the designated id.
     */
    public void setName(String n) {
        name = n;
    }

    /**
     * Retrieve the task's name.<p/>
     *
     * @EFFECTS Return the identification string of this task.
     */
    public String getName() {
        return name;
    }

    /**
     * Limited debugging/tracing support.  If debugging is turned on
     * (debug == true), then print out the message passed in.  <p/>
     *
     * @REQUIRES mess is the message to be print.<p/>
     *
     * @MODIFIES prints the message, mess, out if debug == true.
     */
    protected void printDebug(String mess) {
        if (debug) {
            System.out.println(mess);
        }
    }

    /**
     * A boolean flag to signify if the task been terminated.  This
     * can be used to recognize if "stale" (already removed) tasks are
     * in the runqueue, so as to not run them.
     */
    protected boolean terminated = false;

    /**
     * Track if a task has been terminated.  If so, return true, else
     * false.  <p/>
     * 
     * @EFFECTS return true if this task has been terminated, false
     * otherwise.
     */
    public boolean isTerminated() {
        return terminated;
    }

    /**
     * This method is a means for children to notify parents of their
     * concurrency level, so that the parent (scheduler) can make
     * informed decisions about where to allocate threads.  This is
     * the means for informing schedulers if tasks are blocked or
     * enabled.  Invoking childConcurrencyLevel will update the
     * specified task's concurrency value, and pass this value to the
     * child's parent via the parent's childConcurrencyLevel method
     * (thus making recursive calls down to the ThreadManager).<p/>
     *
     * @REQUIRES child is the task which we are going to update the
     * concurrency of, and concurrency is the concurrency value which
     * that child currently requests.  child must be a task within the
     * Scheduling structures of this (Sched)Task.<p/>
     *
     * @MODIFIES update the concurrency level of child to concurrency,
     * compute the total concurrency at this task, and call
     * recursively the childConcurrencyLevel of this task's parent.<p/>
     */
    abstract protected void childConcurrencyLevel(Task child, int concurrency);

    /**
     * This method enables the Command (in the case of OpcodeTask) and
     * Strategy (in the case of SchedTask) design patterns, and must
     * be overridden by subclasses.  executeTask is invoked when this
     * task is to run.<p/>
     *
     * @EFFECTS Return true if the task can run again immediately, or
     * false if it will block.  Schedulers often can run again if they
     * have any tasks in their runqueue, while opcode tasks must block
     * returning false waiting to be enabled.<p/>
     *
     * @MODIFIES execute the defined functionality of the Task.
     */
    abstract public boolean executeTask();

    /** 
     * Terminate this task. <p/>
     *
     * @MODIFIES Terminate this task such that it will not make any
     * more concurrency requests to its parent, and will, in fact, not
     * maintain a parent any longer.
     */
    abstract public void endTask();
}
